#include "Object.h"

bool Container<Object>::Add(const Object &NewObject)
{
	Object **OldList = Objects;
	Objects = new Object*[++Count];
	if(!Objects)
	{
		Objects = OldList;
		Count--;
		return false;
	}
	for(int i = 0; i < Count-1; i++)
		Objects[i] = OldList[i];
	Objects[Count-1] = new Object(Parent);
	if(!Objects[Count-1])
	{
		Count--;
		delete[] Objects;
		Objects = OldList;
		return false;
	}
	if(OldList)
		delete[] OldList;
	*Objects[Count-1] = NewObject;

	return true;
}

Object & Container<Object>::operator[] (const Value &Index) const 
{
	if(Index.GetType() == AT_INT)
	{
		if( Index.ToInt() < 0 || Index.ToInt() >= Count)
			return *Error;	
		return *Objects[Index.ToInt()];
	}
	else if(Index.GetType() == AT_STRING)
	{
		for(int i = 0; i < Count; i++)
		{
			if(Objects[i]->GetBaseAttribute("Name") == Index)
				return *Objects[i];
		}
	}
	return *Error;
}

bool Container<Object>::RemoveAtIndex(const Value &Index)
{
	if(Index.GetType() == AT_INT && Index.ToInt() >= Count)
		return false;
	T **OldList = Objects;
	Objects = new T*[--Count];
	if(!Objects)
	{
		Count++;
		Objects = OldList;
		return false;
	}
	bool Found = false;
	for(int i = 0; i < Count; i++)
	{
		if(Index.GetType() == AT_INT)
			if(!Found && i == Index.ToInt())
			{
				Found = true;
				delete OldList[i];
			}

		if(Index.GetType() == AT_STRING)
			if(!Found && OldList[i]->GetBaseAttribute("Name") == Index)
			{
				Found = true;
				delete OldList[i];
			}
		if(Found)
			Objects[i] = OldList[i+1];
		else
			Objects[i] = OldList[i];
	}
	if(OldList)
		delete[] OldList;
	return true;
}

bool Container<Object*>::Add(Object &NewObject)
{
	Object **OldList = Objects;
	Objects = new Object*[++Count];
	if(!Objects)
	{
		Objects = OldList;
		Count--;
		return false;
	}
	for(int i = 0; i < Count-1; i++)
		Objects[i] = OldList[i];
	NewObject.Parent = Parent;
	if(!Objects[Count-1])
	{
		Count--;
		delete[] Objects;
		Objects = OldList;
		return false;
	}
	if(OldList)
		delete[] OldList;
	Objects[Count-1] = &NewObject;

	return true;
}

Object & Container<Object*>::operator[] (const Value &Index) const 
{
	if(Index.GetType() == AT_INT)
	{
		if( Index.ToInt() < 0 || Index.ToInt() >= Count)
			return *Error;	
		return *Objects[Index.ToInt()];
	}
	else if(Index.GetType() == AT_STRING)
	{
		for(int i = 0; i < Count; i++)
		{

			if(Objects[i]->GetBaseAttribute("Name") ==  Index)
				return *Objects[i];
		}
	}
	return *Error;
}

bool Container<Object*>::RemoveAtIndex(const Value &Index)
{
	if(Index.GetType() == Index.ToInt() >= Count)
		return false;
	T **OldList = Objects;
	Objects = new T*[--Count];
	if(!Objects)
	{
		Count++;
		Objects = OldList;
		return false;
	}
	bool Found = false;
	for(int i = 0; i < Count; i++)
	{
		if(Index.GetType() == AT_INT)
			if(!Found && i == Index.ToInt())
				Found = true;
		if(Index.GetType() == AT_STRING)
			if(!Found && OldList[i]->GetBaseAttribute("Name") == Index)
				Found = true;
		if(Found)
			Objects[i] = OldList[i+1];
		else
			Objects[i] = OldList[i];
	}
	if(OldList)
		delete[] OldList;
	return true;
}

Value Object::Error("Name", "Error");

Object::Object(Object *NewParent)
{
	Parent = NewParent;
	Children.Parent = this;
	Index = -1;
}

Object::Object(const Object &Source)
{
	Children.Parent = this;
	Index = -1;
	Copy(Source);
}

Value &Object::GetBaseAttribute(const Value &Name)
{
	if(Name.GetType() == AT_INT)
		if(Name.ToInt() < Attributes.Size() && Name.ToInt() >= 0)
			return Attributes[Name.ToInt()];
		else
			return Error;
	for(int i = 0; i < Attributes.Size(); i++)
	{
		if(strcmp(Attributes[i].name,Name.ToCharPtr()) == 0)
			return Attributes[i];
	}
	return Error;
}

Value Object::GetModifiedAttribute(const Value &Name)
{
	Value Return = GetBaseAttribute(Name);
	if(strcmp(Return.name, "Error") == 0)
		return Return;

	for(int i = 0; i < Effects.Size(); i++)
	{
		for(int j = 0; j < Effects[i].Attributes.Size(); j++)
		{
			if(strcmp(Effects[i].Attributes[j].name, Name.ToCharPtr()) == 0)
			{
				Return += Effects[i].Attributes[j];
			}
		}
	}

	return Return;
}

Object &Object::operator=(const Object &Source)
{
	Copy(Source);
	return *this;
}

Object &Object::operator [](const Value &Index)
{
	if(Children[Index].GetBaseAttribute("Name") == "Error")
		return *Container<Object>::Error;
	return Children[Index];
}

Container<Object *> Object::GetObjectsWithAttribute(const Value &Index)
{
	Container<Object *> Return;

	for(int i = 0; i < Children.Size(); ++i)
	{
		for(int j = 0; j < Children[i].Attributes.Size(); ++j)
		{
			if(strcmp(Children[i].Attributes[j].name, Index.name) == 0)
			{
				if(Children[i].Attributes[j] == Index)
				{
					Return.Add(&Children[i]);
					break;
				}
			}
		}
	}

	return Return;
}

Container<Object *> Object::GetObjectsWithAttributes(Container<Value> Indexs)
{
	Container<Object *> Returns;

	if(Indexs.Size() <= 0)
		return Returns;

	char *In = new char[Children.Size()];
	memset(In, 1, Children.Size());

	for(int i = 0; i < Indexs.Size(); ++i)
	{
		for(int j = 0; j < Children.Size(); ++j)
		{
			if(!In[j])
				continue;
			if(strcmp(Children[j].GetBaseAttribute(Indexs[i].name).name , "Error") == 0)
			{
				In[j] = 0;
			}
			else if(Children[j].GetBaseAttribute(Indexs[i].name) != Indexs[i])
			{
				In[j] = 0;
			}
		}
	}

	for(int i = 0; i < Children.Size(); ++i)
		if(In[i])
			Returns.Add(Children[i]);

	return Returns;
}

void Object::Copy(const Object& Source)
{
	Children.Clear();
	Attributes.Clear();
	Effects.Clear();
	Events.Clear();
	Parent = Source.Parent;
	Children = Source.Children;
	Attributes = Source.Attributes;
	Effects = Source.Effects;
	Events = Source.Events;
	Index = Source.Index;
}

int Object::GetIndex()
{
	return Index;
}